<template>
    <div class="scrollbar" :scrolling-y="scrollingY" :scrolling-x="scrollingX">
        <div class="scrollbar-content" ref="outer" @scroll="onScroll($event)">
            <div class="scrollbar-scroller" ref="inner">
                <slot />
            </div>
        </div>
        <div class="scrollbar-vertical">
            <span class="scrollbar-thumb" :style="verticalThumb" @mousedown="onMouseDown($event,'vertical')"></span>
        </div>
        <div class="scrollbar-horizontal">
            <span class="scrollbar-thumb"></span>
        </div>
    </div>
</template>
<script>
export default {
    props: {
        horizontal: { type: Boolean, default: false },
        vertical: { type: Boolean, default: false },
    },
    data () {
        return {
            outer_width: 0,
            outer_height: 0,
            inner_width: 0,
            inner_height: 0,
            inner_top: 0,
            inner_left: 0,
            interval: [],
            drag: { type: '', inner_top: 0, inner_left: 0, clientX: 0, clientY: 0 },
            scrolling: { vertical: 0, horizontal: 0, },
        };
    },
    computed: {

        // 竖的滑块
        verticalThumb () {
            if (this.inner_height) {
                return {
                    height: 100 * this.outer_height / this.inner_height + '%',
                    top: 100 * this.inner_top / this.inner_height + '%',
                }
            }
        },

        scrollingX () {
            return this.scrolling.horizontal > 0 || (this.drag && this.drag.type == 'horizontal')
        },
        scrollingY () {
            return this.scrolling.vertical > 0 || (this.drag && this.drag.type == 'vertical')
        }
    },

    methods: {

        // 修改的内容
        onOuterResize (width, height) {
            this.outer_width = width;
            this.outer_height = height;
        },

        onInnerResize (width, height) {
            this.inner_width = width;
            this.inner_height = height;
        },

        // 滚动事件
        onScroll (event) {

            if (this.inner_top != event.target.scrollTop) {
                this.inner_top = event.target.scrollTop
                this.scrolling.vertical && clearTimeout(this.scrolling.vertical);
                this.scrolling.vertical = setTimeout(() => this.scrolling.vertical = 0, 1500);
            }

            if (this.inner_left != event.target.scrollLeft) {
                this.inner_left = event.target.scrollLeft
                this.scrolling.horizontal && clearTimeout(this.scrolling.horizontal);
                this.scrolling.horizontal = setTimeout(() => this.scrolling.horizontal = 0, 1500);
            }
        },

        // 鼠标按下
        onMouseDown (event, type) {
            this.drag.type = type;
            this.drag.inner_top = this.inner_top;
            this.drag.inner_left = this.inner_left;
            this.drag.clientX = event.clientX;
            this.drag.clientY = event.clientY;
        },

        // 鼠标滚动
        onMouseMove (event) {
            if (!this.drag.type || !this.$refs.outer) {
                // 没有
            } else if (this.drag.type == 'vertical') {
                const offsetY = event.clientY - this.drag.clientY;
                const top = Math.max(0, Math.min(this.inner_height - this.outer_height, this.drag.inner_top + offsetY))
                this.$refs.outer.scrollTop = top
                this.inner_top = top
            } else if (this.drag.type == 'horizontal') {
                const offsetX = event.clientX - this.drag.clientX;
                const left = Math.max(0, Math.min(this.inner_width - this.outer_width, this.drag.inner_left + offsetX))
                this.$refs.outer.scrollLeft = left
                this.inner_left = left
            }
        },

        // 鼠标弹起
        onMouseUp () {
            this.drag.type && (this.drag.type = '')
        },

        // 监听事件
        addEventListener (el, callback) {
            if (!el) {
                // 没有节点
            } else if (ResizeObserver) {
                new ResizeObserver(() => {
                    const size = el.getBoundingClientRect()
                    callback && callback(size.width, size.height)
                }).observe(el)
            } else {
                const cache = { width: 0, height: 0 }
                const interval = () => {
                    const size = el.getBoundingClientRect()
                    if (cache.width !== size.width || cache.height !== size.height) {
                        cache.width = size.width
                        cache.height = size.height;
                        callback && callback(cache.width, cache.height)
                    }
                }
                this.interval.push(setInterval(interval, 16))
            }
        }
    },
    mounted () {
        this.addEventListener(this.$refs.inner, this.onInnerResize)
        this.addEventListener(this.$refs.outer, this.onOuterResize)
        this.inner_top = this.$refs.outer.scrollTop || 0;
        this.inner_left = this.$refs.outer.scrollLeft || 0;
        window.addEventListener('mousemove', this.onMouseMove)
        window.addEventListener('mouseup', this.onMouseUp)
    },
    beforeDestroy () {
        this.interval.map(i => clearInterval(i))
        this.interval = []
        window.removeEventListener('mousemove', this.onMouseMove)
        window.removeEventListener('mouseup', this.onMouseUp)
    }
};
</script>
<style lang="scss" scoped>
.scrollbar {
    position: relative;
    display: flex;

    &[scrolling-y] .scrollbar-vertical {
        opacity: 1;
        pointer-events: all;
    }

    &[scrolling-x] .scrollbar-horizontal {
        opacity: 1;
        pointer-events: all;
    }
}

.scrollbar-content {
    overflow: auto;
    flex: 1;
    width: 100%;
    position: relative;
    &::-webkit-scrollbar {
        display: none;
    }

    &::-webkit-scrollbar-track {
        background-color: #e8e8e8;
        border: none;
        display: none;
    }

    &::-webkit-scrollbar-thumb {
        background-color: #c0c0c0;
        border-radius: 10px;
        width: 0;
        height: 0;
    }

    &::-webkit-scrollbar-thumb:hover {
        background-color: #c0c0c0;
        border-radius: 10px;
    }
}

.scrollbar-scroller {
    position: absolute;
    left: 0;
    top: 0;
    min-width: 100%;
    min-height: 100%;
}

.scrollbar-vertical {
    position: absolute;
    right: 0;
    top: 0;
    height: 100%;
    width: 10px;
    opacity: 0;
    transition: opacity 0.5s;
    pointer-events: none;

    &:hover {
        pointer-events: all;
        opacity: 1;
    }

    span {
        position: absolute;
        left: 50%;
        top: 0;
        width: 8px;
        margin-left: -4px;
        border-radius: 5px;
        cursor: pointer;
        background-color: rgba(0, 0, 0, 0.5);
    }
}
</style>
